package com.startest.sms.utils;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.*;

/**
 * Created by cly on 2018/11/29.
 */
public class RSAUtil {

    /**
     * byte转string
     * @param bytes
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String encodeBase64(byte[] bytes) throws UnsupportedEncodingException {
        return new String(Base64.encodeBase64(bytes),"UTF-8");
    }

    /**
     * string转bytes
     * @param str
     * @return
     * @throws UnsupportedEncodingException
     */
    public static byte[] decodeBase64(String str) throws UnsupportedEncodingException {
        return Base64.decodeBase64(str.getBytes("UTF-8"));
    }

    /**
     * 生成密钥对
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA",new BouncyCastleProvider());
        keyPairGen.initialize(1024,new SecureRandom());
        return keyPairGen.generateKeyPair();
    }


    /**
     * 通过公钥bytes 返回公钥
     * @param keyBytes
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static PublicKey getPublicKey(byte[] keyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 通过私钥bytes 返回私钥
     * @param keyBytes
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static PrivateKey getPrivateKey(byte[] keyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = factory.generatePrivate(keySpec);
        return privateKey;
    }

    /**
     * 获取公钥  通过N e 值
     * @param modulus   N
     * @param publicExponent e
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static RSAPublicKey getPublicKey(byte[] modulus,byte[] publicExponent) {

        KeyFactory keyFactory = null;
        try {
            keyFactory = KeyFactory.getInstance("RSA",new BouncyCastleProvider());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(publicExponent));
        RSAPublicKey rsaPublicKey = null;
        try {
            rsaPublicKey = (RSAPublicKey)keyFactory.generatePublic(publicKeySpec);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return rsaPublicKey;
    }

    /**
     * 通过N e 值获取私钥
     * @param modulus
     * @param privateExponent
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static RSAPrivateKey getPrivateKey(byte[] modulus,byte[] privateExponent){
        BigInteger bigIntegerModulus = new BigInteger(modulus);
        BigInteger bigIntegerExponent = new BigInteger(privateExponent);
        RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(bigIntegerModulus, bigIntegerExponent);

        KeyFactory factory = null;
        try {
            factory = KeyFactory.getInstance("RSA",new BouncyCastleProvider());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        RSAPrivateKey rsaPrivateKey = null;
        try {
            rsaPrivateKey = (RSAPrivateKey)factory.generatePrivate(privateKeySpec);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return rsaPrivateKey;
    }

    /**
     * 加密
     * @param publicKey
     * @param data
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public static byte[] encrypt(PublicKey publicKey,byte[] data) throws Exception{
        if(publicKey!=null){
            Cipher cipher = Cipher.getInstance("RSA",new BouncyCastleProvider());
            cipher.init(Cipher.ENCRYPT_MODE,publicKey);
            int blockSize = cipher.getBlockSize();//获取加密块大小， 加密前数据为128byte，而key_size=1024
            int outputSize = cipher.getOutputSize(data.length);
            int leavedSize = data.length % blockSize;
            int bSize = leavedSize!=0?data.length / blockSize + 1:data.length / blockSize;
            byte[] raw = new byte[outputSize * bSize];
            int i=0;
            while (data.length-i*blockSize>0){
                if(data.length-i*blockSize>bSize){
                    cipher.doFinal(data,i*blockSize,blockSize,raw,i*outputSize);
                }else{
                    cipher.doFinal(data,i*blockSize,data.length-i*blockSize,raw,i*outputSize);
                }
                i++;
            }
            return raw;
        }
        return null;
    }

    /**
     * 解密
     * @param privateKey
     * @param data
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public static byte[] decrypt(PrivateKey privateKey,byte[] data) throws Exception{
        if(privateKey!=null){
            Cipher cipher = Cipher.getInstance("RSA",new BouncyCastleProvider());
            cipher.init(Cipher.DECRYPT_MODE,privateKey);
            int blockSize = cipher.getBlockSize();
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream(64);
            int j=0;
            while(data.length-j*blockSize>0){
                outputStream.write(cipher.doFinal(data,j*blockSize,blockSize));
                j++;
            }
            return outputStream.toByteArray();
        }
        return null;
    }


    public static void main(String[] args) throws NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException, IOException {
        String str = "123qwe";
        //创建类对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        //初始化密钥生成器
        keyPairGen.initialize(1024);
        //生成密钥对保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        //公钥
        RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
        System.out.println(encodeBase64(publicKey.getEncoded()));
        //私钥
        RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
        System.out.println(encodeBase64(privateKey.getEncoded()));


        System.out.println("dadsda".getBytes().length);
       // String pubstr = publicKey.getPublicExponent().toString(16); //e
        //String pubMod = publicKey.getModulus().toString(16);   //N

    }


}
